/**
 * 
 */
package com.cnhaimei.com;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;

/**
 * @author Jin.Wu
 * 
 */
public class DragView extends RelativeLayout {
	private static final String TAG = "DragView";
	private static final int SCROLL_WAITING_IN_ZONE = 1;
	private static final int SCROLL_OUTSIDE_ZONE = 0;
	
	private static final float DRAG_SCALE = -24.0f;
	private static final int SCROLL_DELAY = 700;
	private static final int SCROLL_ZONE = 40;
	
	Bitmap mDragBitmap;
	private float mLastMotionX;
	private float mLastMotionY;
	private float mTouchOffsetX;
	private float mTouchOffsetY;
	private View mOriginator;
	private int mBitmapOffsetX;
	private int mBitmapOffsetY;
	private Rect mDragRect = new Rect();
	private final Rect mRect = new Rect();
	int ox;
	int oy;
	private boolean mDragging;
	private boolean mShouldDrop;
	private int mScrollState = SCROLL_OUTSIDE_ZONE;


	private Paint mDragPaint;
	private DropListener dropListener;
	private ScrollListener scrollListener;
	private ScrollRunnable mScrollRunnable = new ScrollRunnable();

	public DragView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public DragView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public DragView(Context context) {
		super(context);
	}

	public void setPosition(int x, int y) {
		this.ox = x;
		this.oy = y;
		this.postInvalidate();
	}

	public void move(int mx, int my) {
		this.ox += mx;
		this.oy += my;
		this.postInvalidate();
	}
	
	public boolean isDragging() {
		return mDragging;
	}

	@Override
	public boolean dispatchKeyEvent(KeyEvent event) {
		return mDragging || super.dispatchKeyEvent(event);
	}
	
//	public boolean dispatchTouchEvent(MotionEvent event) {
//		return mDragging || super.dispatchTouchEvent(event);
//	}

	@Override
	protected void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
		if (mDragging && mDragBitmap != null) {


			int mScrollX = getScrollX();
			int mScrollY = getScrollY();
			canvas.drawBitmap(mDragBitmap, mScrollX + mLastMotionX
					- mTouchOffsetX - mBitmapOffsetX, mScrollY
					+ mLastMotionY - mTouchOffsetY - mBitmapOffsetY,
					mDragPaint);
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		if (!mDragging) {
			return false;
		}

		final int action = ev.getAction();
		final float x = ev.getX();
		final float y = ev.getY();

		switch (action) {
		case MotionEvent.ACTION_DOWN:
			
			mLastMotionX = x;
			mLastMotionY = y;

			break;
		case MotionEvent.ACTION_MOVE:
//			Log.e(TAG, "x:" + x + "y:" + y);
			final int scrollX = getScrollX();
			final int scrollY = getScrollY();

			final float touchX = mTouchOffsetX;
			final float touchY = mTouchOffsetY;

			final int offsetX = mBitmapOffsetX;
			final int offsetY = mBitmapOffsetY;

			int left = (int) (scrollX + mLastMotionX - touchX - offsetX);
			int top = (int) (scrollY + mLastMotionY - touchY - offsetY);

			final Bitmap dragBitmap = mDragBitmap;
			final int width = dragBitmap.getWidth();
			final int height = dragBitmap.getHeight();

			final Rect rect = mRect;
			rect.set(left - 1, top - 1, left + width + 1, top + height + 1);

			mLastMotionX = x;
			mLastMotionY = y;

			left = (int) (scrollX + x - touchX - offsetX);
			top = (int) (scrollY + y - touchY - offsetY);

			// Invalidate current icon position
		//	rect.union(left - 1, top - 1, left + width + 1, top + height + 1);

			invalidate();

			if (x < SCROLL_ZONE && mScrollState == SCROLL_OUTSIDE_ZONE) {
				
				mScrollState = SCROLL_WAITING_IN_ZONE;
				mScrollRunnable.setDirection(true);
				postDelayed(mScrollRunnable, SCROLL_DELAY);
				
			} else if ((x > getWidth() - SCROLL_ZONE) && mScrollState == SCROLL_OUTSIDE_ZONE){
				Log.e(TAG, "in");
				mScrollState = SCROLL_WAITING_IN_ZONE;
				mScrollRunnable.setDirection(false);
				postDelayed(mScrollRunnable, SCROLL_DELAY);
				
			} else if((x > SCROLL_ZONE && (x < getWidth() - SCROLL_ZONE))
					&& mScrollState == SCROLL_WAITING_IN_ZONE){
				mScrollState = SCROLL_OUTSIDE_ZONE;
//				Log.e(TAG, "out");
				removeCallbacks(mScrollRunnable);
			} else {
//				Log.e(TAG, "no");
			}

			break;
		case MotionEvent.ACTION_UP:
//			removeCallbacks(mScrollRunnable);
			if (mShouldDrop) {
				drop(x, y);
				mShouldDrop = false;
			}
			endDrag();

			break;
		case MotionEvent.ACTION_CANCEL:
			if (mScrollState == SCROLL_WAITING_IN_ZONE) {
				removeCallbacks(mScrollRunnable);
			}
			endDrag();
		}

		return true;
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		final int action = ev.getAction();

		final float x = ev.getX();
		final float y = ev.getY();

		switch (action) {
		case MotionEvent.ACTION_MOVE:
			break;

		case MotionEvent.ACTION_DOWN:
			// Remember location of down touch
			mLastMotionX = x;
			mLastMotionY = y;
			break;

		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
			if (mShouldDrop && drop(x, y)) {
				mShouldDrop = false;
			}
			endDrag();
			break;
		}

		return mDragging;
	}

	public void startDrag(View v, int touchX, int touchY) {

		Rect r = mDragRect;
		r.set(v.getScrollX(), v.getScrollY(), 0, 0);

		mTouchOffsetX = 0;//mLastMotionX - touchX;
		mTouchOffsetY = 0;//mLastMotionY - touchY;

		v.clearFocus();
		v.setPressed(false);

		boolean willNotCache = v.willNotCacheDrawing();
		v.setWillNotCacheDrawing(false);

		// Reset the drawing cache background color to fully transparent
		// for the duration of this operation
		int color = v.getDrawingCacheBackgroundColor();
		v.setDrawingCacheBackgroundColor(0);

		if (color != 0) {
			v.destroyDrawingCache();
		}
		v.buildDrawingCache();
		Bitmap viewBitmap = v.getDrawingCache();
		int width = viewBitmap.getWidth();
		int height = viewBitmap.getHeight();

		Matrix scale = new Matrix();
		float scaleFactor = v.getWidth();
		scaleFactor = (scaleFactor + DRAG_SCALE) / scaleFactor;
		scale.setScale(scaleFactor, scaleFactor);

		mDragBitmap = Bitmap.createBitmap(viewBitmap, 0, 0, width, height,
				scale, true);
		v.destroyDrawingCache();
		v.setWillNotCacheDrawing(willNotCache);
		v.setDrawingCacheBackgroundColor(color);

		final Bitmap dragBitmap = mDragBitmap;
		mBitmapOffsetX = (dragBitmap.getWidth() )/ 2;// - width) / 2;
		mBitmapOffsetY = (dragBitmap.getHeight()* 3) / 4;// - height) / 2;

		mDragging = true;
		mShouldDrop = true;
		mOriginator = v;

		invalidate();
	}

	private boolean drop(float x, float y) {
		invalidate();
		if (dropListener != null) {
			dropListener.onDrop(x, y);
			return true;
		}
		return false;
	}

	private void endDrag() {
		if (mDragging) {
			mDragging = false;
			if (mDragBitmap != null) {
				mDragBitmap.recycle();
			}
			if (mOriginator != null) {
				mOriginator.setVisibility(VISIBLE);
			}
		}
	}

	public DropListener getDropListener() {
		return dropListener;
	}

	public void setDropListener(DropListener dropListener) {
		this.dropListener = dropListener;
	}
	
	public ScrollListener getScrollListener() {
		return scrollListener;
	}

	public void setScrollListener(ScrollListener scrollListener) {
		this.scrollListener = scrollListener;
	}

	public interface DropListener {
		void onDrop(float x, float y);
	}
	
	public interface ScrollListener {
		void onScroll( boolean isLeft);
	}
	
	private class ScrollRunnable implements Runnable {
		private boolean isLeft;

		ScrollRunnable() {
		}

		public void run() {
			if (scrollListener != null) {
				scrollListener.onScroll(isLeft);
				mScrollState = SCROLL_OUTSIDE_ZONE;
			}
		}

		void setDirection(boolean isLeft) {
			this.isLeft = isLeft;
		}
	}

}
